Skip to content

Fix GH-20214: PDO::FETCH_DEFAULT unexpected behavior with setFetchMode#21434

Open
iliaal wants to merge 3 commits intophp:PHP-8.4from
iliaal:fix/gh-20214-pdo-fetch-default
Open

Fix GH-20214: PDO::FETCH_DEFAULT unexpected behavior with setFetchMode#21434
iliaal wants to merge 3 commits intophp:PHP-8.4from
iliaal:fix/gh-20214-pdo-fetch-default

Conversation

@iliaal
Copy link
Copy Markdown
Contributor

@iliaal iliaal commented Mar 13, 2026

When setFetchMode(PDO::FETCH_DEFAULT) is called, pdo_stmt_setup_fetch_mode() stores PDO_FETCH_USE_DEFAULT (0) as the statement's default fetch type. Later, do_fetch() tries to resolve PDO_FETCH_USE_DEFAULT by reading stmt->default_fetch_type — which is also 0, creating a circular reference. On 8.4 this silently fell through to FETCH_BOTH; on master it throws a ValueError.

The fix resolves PDO_FETCH_USE_DEFAULT to the connection-level default (stmt->dbh->default_fetch_type) early in pdo_stmt_setup_fetch_mode(), before flags extraction and the mode switch. The connection default is guaranteed to never be PDO_FETCH_USE_DEFAULT (enforced by PDO::setAttribute), so no circular resolution is possible.

Not sure if this should be rebased to the PHP-8.4 branch since the bug affects 8.4 as well (silently returns wrong fetch mode there).

Fixes #20214

Copy link
Copy Markdown
Member

@SakiTakamachi SakiTakamachi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes!
I’ve left a few minor comments, but I agree with the overall approach.

@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Apr 3, 2026

Good catches.

The flags issue was a real bug. I moved the resolution after flags extraction so caller-supplied flags like PDO_FETCH_GROUP are preserved:

flags = mode & PDO_FETCH_FLAGS;

if ((mode & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
    mode = stmt->dbh->default_fetch_type | flags;
}

Moved the test to ext/pdo/tests/ and added cases for query() with a second argument and for flags preservation through the default resolution path.

@SakiTakamachi
Copy link
Copy Markdown
Member

@iliaal
Thank you!
And it looks like it’s fine to target the 8.4 branch.

iliaal added 2 commits April 3, 2026 09:26
…ment::setFetchMode

When setFetchMode(PDO::FETCH_DEFAULT) is called, mode=0
(PDO_FETCH_USE_DEFAULT) gets stored as the statement's default fetch
type. Later, do_fetch() tries to resolve PDO_FETCH_USE_DEFAULT by
reading stmt->default_fetch_type, which is also 0 — circular
reference that on 8.4 silently fell through to FETCH_BOTH and on
master throws a ValueError.

Resolve PDO_FETCH_USE_DEFAULT to the connection-level default early in
pdo_stmt_setup_fetch_mode(), before flags extraction and the mode
switch, so the rest of the function processes the actual fetch mode.

Closes phpGH-20214
Extract flags before resolving PDO_FETCH_USE_DEFAULT so caller-supplied
flags (e.g. PDO_FETCH_GROUP) are preserved. Move test from pdo_sqlite to
ext/pdo/tests/ for cross-driver coverage. Add test cases for query()
with second argument and flags preservation.
@iliaal iliaal changed the base branch from master to PHP-8.4 April 3, 2026 13:31
@iliaal iliaal force-pushed the fix/gh-20214-pdo-fetch-default branch from 2d59faa to 40868e4 Compare April 3, 2026 13:31
@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Apr 3, 2026

@iliaal Thank you! And it looks like it’s fine to target the 8.4 branch.

@SakiTakamachi I ported the code to 8.4 all the PDO tests pass, however FreeBSD seems to abort with infra error and in other environments un-related ssl (flaky??) tests seem to be failing which are not at all related to this change.

@iliaal iliaal requested a review from SakiTakamachi April 3, 2026 13:49
@iliaal iliaal force-pushed the fix/gh-20214-pdo-fetch-default branch from 7196192 to 742500d Compare April 8, 2026 11:22
Firebird requires SELECT ... FROM table syntax; bare SELECT 'val' AS col
is not valid. Create a test table to make the test cross-driver compatible.
@iliaal iliaal force-pushed the fix/gh-20214-pdo-fetch-default branch from 742500d to 9fbac37 Compare April 8, 2026 11:23
@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Apr 8, 2026

@SakiTakamachi looks to be ready for 8.4 inclusion, unfortunately there seems to be some CI/CD issue with unrelated openssl test causing failure on [ci/circleci: arm], tried re-triggering the CI to no avail...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PDO::FETCH_DEFAULT unexpected behavior with PDOStatement::setFetchMode

2 participants